package com.capinfo.commons.project.model.region;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Where;

import com.capinfo.framework.model.StatusEnabled;
import com.capinfo.framework.service.GeneralService;


/**
 * <p>
 * 行政区域
 * </p>
 * 
 * @version 1.0
 * @author 张名扬
 */

@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table(name = "REGIONS")
@SequenceGenerator(name = "seqRegions", sequenceName = "SEQ_REGIONS", allocationSize=1)
public class Region implements StatusEnabled, com.capinfo.framework.model.system.Region<Region> {

	public final static Long ROOT_ID = 1000L;
	// Fields

	private Long id;

	private Long parentId;

	private Region parent;

	// 区域名称。
	private String name;

	// 级别 1-市级  2-区县级  3-街道级（乡镇）  4-社区级（村）
	private Short level;

	// 区域编码。
	private String standardcode;
	
	private String description;

	private List<Region> children = new ArrayList<Region>();
	
	
	// 是否可用 1-可用 0-不可用。
	private Boolean enabled = true;

	public Region() {
	}
	
	@Transient
	public Long getRootId() {
		return ROOT_ID;
	}
	
	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator ="seqRegions")
	@Column(name = "ID", unique = true, nullable = false, precision = 12, scale = 0)
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@ManyToOne(targetEntity = Region.class, fetch = FetchType.LAZY)
	@JoinColumn(name = "PARENT_ID")
	public Region getParent() {
		return parent;
	}

	public void setParent(Region parent) {
		this.parent = parent;
	}

	@Column(name = "PARENT_ID", nullable = false, precision = 12, scale = 0, insertable = false, updatable = false)
	public Long getParentId() {
		return parentId;
	}

	public void setParentId(Long parentId) {
		this.parentId = parentId;
	}

	@Column(name = "NAME_", length = 50)
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Column(name = "RANK", nullable = false, length = 2)
	public Short getLevel() {
		return level;
	}

	public void setLevel(Short level) {
		this.level = level;
	}

	@Column(name = "STANDARD_CODE", nullable = false, length = 30)
	public String getStandardcode() {
		return standardcode;
	}

	public void setStandardcode(String standardcode) {
		this.standardcode = standardcode;
	}
	
	@Column(name = "DESCRIPTION", length = 256)
	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	@OneToMany(targetEntity = Region.class, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JoinColumn(name = "PARENT_ID")
	@Where(clause = "ENABLED = '1'")
	@OrderBy(value = "id asc")
	public List<Region> getChildren() {
		return children;
	}

	public void setChildren(List<Region> children) {
		this.children = children;
	}

	@Column(name = "ENABLED", precision = 1, scale = 0)
	public Boolean getEnabled() {
		return enabled;
	}

	public void setEnabled(Boolean enabled) {
		this.enabled = enabled;
	}
	
	@Transient
	public String getHierarchicalName() {

		StringBuilder cascadeName = new StringBuilder();
		switch (getLevel().intValue()) {

			case 4:
	
				cascadeName.append(((Region) getParent().getParent()).getName()
						+ "-");
			case 3:
	
				cascadeName.append(((Region) getParent()).getName() + "-");
			default:
	
				cascadeName.append(getName());
				break;
		}

		return cascadeName.toString();
	}
	
	/**
	 * 
	 * <p>
	 * 当从session等内存中取回保存的region对象后，再去调用“getHierarchicalName”方法，
	 * 就会出现延迟加载的数据不在一个会话的问题，这时可以通过调用这个方法解决。
	 * </p>
	 * 
	 * @param generalService
	 */
	@Transient
	public void initLoadAncestry(GeneralService generalService) {

		Region that = this;
		for(int i = getLevel().intValue(); i > 2; i--) {
			
			try{
				
				that.getParent().toString();
			} catch(Exception e) {
				
				generalService.fetchLazyProperty(that, "parent");
			}
			
			that = that.getParent();
		}
	}

	public String toString() {

		return new ToStringBuilder(this).append("id", getId()).append("name",
				getName()).append("standardcode", getStandardcode()).append(
				"level", getLevel()).toString();
	}

	public boolean equals(Object other) {

		if ((this == other))
			return true;
		if (!(other instanceof Region))
			return false;

		Region castOther = (Region) other;
		return new EqualsBuilder().append(this.getId(), castOther.getId()).isEquals();
	}

	public int hashCode() {

		return new HashCodeBuilder().append(getId()).toHashCode();
	}

}